package com.bestvike.stone.spring.client;

import com.bestvike.stone.core.collection.MapUtils;
import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.spring.exception.BusinessException;
import com.bestvike.stone.spring.exception.ErrorCode;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Map;

/**
 * Created by 许崇雷 on 2018-02-23.
 */
@Component
public final class RestTemplateUtils {
    private static final String ERROR_SERVER_MSG = "外部服务发生错误:HTTP-%s";
    private static final String ERROR_NULL_MSG = "外部服务未返回任何数据";
    private static RestTemplate ribbonJsonRestTemplate;
    private static RestTemplate ribbonXmlRestTemplate;
    private static RestTemplate jsonRestTemplate;
    private static RestTemplate xmlRestTemplate;

    RestTemplateUtils(RestTemplate ribbonJsonRestTemplateInstance,
                      @Qualifier("ribbonXmlRestTemplate") RestTemplate ribbonXmlRestTemplateInstance,
                      @Qualifier("jsonRestTemplate") RestTemplate jsonRestTemplateInstance,
                      @Qualifier("xmlRestTemplate") RestTemplate xmlRestTemplateInstance) {
        ribbonJsonRestTemplate = ribbonJsonRestTemplateInstance;
        ribbonXmlRestTemplate = ribbonXmlRestTemplateInstance;
        jsonRestTemplate = jsonRestTemplateInstance;
        xmlRestTemplate = xmlRestTemplateInstance;
    }

    //负载均衡 Json
    public static RestTemplate getRibbonJsonRestTemplate() {
        return ribbonJsonRestTemplate;
    }

    //负载均衡 Xml
    public static RestTemplate getRibbonXmlRestTemplate() {
        return ribbonXmlRestTemplate;
    }

    //非负载均衡 Json
    public static RestTemplate getJsonRestTemplate() {
        return jsonRestTemplate;
    }

    //非负载均衡 Xml
    public static RestTemplate getXmlRestTemplate() {
        return xmlRestTemplate;
    }

    //发起请求并接受响应
    public static <TResponse> TResponse exchange(final RestTemplate restTemplate, final String url, final HttpMethod method, final Object body, final Type responseType, final Map<String, ?> uriVariables, final MultiValueMap<String, String> headers) {
        return exchange(restTemplate, url, method, body, responseType, uriVariables, headers, null, null);
    }

    //发起请求并接受响应
    public static <TResponse> TResponse exchange(final RestTemplate restTemplate, final String url, final HttpMethod method, final Object body, final Type responseType, final Map<String, ?> uriVariables, final MultiValueMap<String, String> headers, final HostnameVerifier hostnameVerifier, final SSLSocketFactory socketFactory) {
        //构建 URI
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
        if (MapUtils.isNotEmpty(uriVariables)) {
            for (Map.Entry<String, ?> entry : uriVariables.entrySet())
                uriBuilder.queryParam(entry.getKey(), Convert.toStringHuman(entry.getValue()));
        }
        URI uri = uriBuilder.build().encode().toUri();
        //响应类型
        boolean returnResponse = false;
        Type responseBodyType = responseType;
        if (responseType instanceof ParameterizedType) {
            ParameterizedType responseParameterizedType = (ParameterizedType) responseType;
            if (responseParameterizedType.getRawType() == ResponseEntity.class) {
                responseBodyType = responseParameterizedType.getActualTypeArguments()[0];
                returnResponse = true;
            }
        }
        ParameterizedTypeReference<TResponse> responseTypeReference = ParameterizedTypeReference.forType(responseBodyType);
        //请求
        ResponseEntity<TResponse> responseEntity = restTemplate.exchange(uri, method, new HttpsEntity<>(body, headers, hostnameVerifier, socketFactory), responseTypeReference);
        //返回
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            if (responseEntity.getBody() == null)
                throw new BusinessException(ErrorCode.ERROR_SERVER, ERROR_NULL_MSG);
            //noinspection unchecked
            return returnResponse ? (TResponse) responseEntity : responseEntity.getBody();
        }
        throw new BusinessException(ErrorCode.ERROR_SERVER, ERROR_SERVER_MSG + responseEntity.getStatusCodeValue());
    }
}
